home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / circuits / irsim-ca.2 / irsim-ca / irsim-cap-9.2 / src / ana11 / window.c < prev    next >
C/C++ Source or Header  |  1993-01-15  |  27KB  |  1,193 lines

  1. /*
  2.  *     ********************************************************************* 
  3.  *     * Copyright (C) 1988, 1990 Stanford University.                     * 
  4.  *     * Permission to use, copy, modify, and distribute this              * 
  5.  *     * software and its documentation for any purpose and without        * 
  6.  *     * fee is hereby granted, provided that the above copyright          * 
  7.  *     * notice appear in all copies.  Stanford University                 * 
  8.  *     * makes no representations about the suitability of this            * 
  9.  *     * software for any purpose.  It is provided "as is" without         * 
  10.  *     * express or implied warranty.  Export of this software outside     * 
  11.  *     * of the United States of America may require an export license.    * 
  12.  *     *********************************************************************
  13.  */
  14.  
  15. /*
  16.  * Window Manager for logic analyzer
  17.  *
  18.  */
  19. #include <stdio.h>
  20. #include "ana.h"
  21. #include <X11/Xutil.h>
  22. #include "graphics.h"
  23. #include "ana_glob.h"
  24.  
  25.  
  26. public    Display     *display = NULL;
  27. public    Screen      *screen;
  28. public    Window      window = 0;
  29. public    Window      iconW = 0;
  30.  
  31. public    int         CHARHEIGHT = 0;
  32. public    int         CHARWIDTH = 0;
  33. public    int        descent;
  34.  
  35. public    Times       tims;
  36. public    Traces      traces;
  37. public    Wstate      windowState = { FALSE, FALSE, FALSE };
  38.  
  39. private    char        *wname = "analyzer";
  40. public    char        *banner;
  41. public    int         bannerLen;
  42.  
  43.  
  44. private    void    DrawSignal(), DrawVector(), EraseCursor(), DrawCursor();
  45. private    void    MoveCursorToPos();
  46.  
  47.  
  48. /*
  49.  * Convert a time to its corresponding x position.
  50.  */
  51. public
  52. #define TimeToX( tm )                            \
  53.     (((tm) - tims.start) * (traceBox.right - traceBox.left - 2) /    \
  54.       tims.steps + traceBox.left + 1 )
  55.  
  56.  
  57. /*
  58.  * Convert an x position to the closest time-step.
  59.  * Return -1 if the point lies outside the traces window.
  60.  */
  61. public TimeType XToTime( x )
  62.   Coord  x;
  63.   {
  64.     float  tmp;
  65.  
  66.     if( (x <= traceBox.left) or (x >= traceBox.right) )
  67.     return( -1 );
  68.     tmp = (float) tims.steps / (traceBox.right - traceBox.left - 2);
  69.     return( tims.start + round( (x - traceBox.left - 1) * tmp ) );
  70.   }
  71.  
  72.  
  73. /*
  74.  * return TRUE if the 2 bounding boxes intersect, otherwise FALSE
  75.  */
  76. #define Intersect( b1, b2 )                        \
  77.     ( ( (b1.top > b2.bot) or (b2.top > b1.bot) or            \
  78.       (b1.left > b2.right) or (b2.left > b1.right ) ) ? FALSE : TRUE )
  79.  
  80.  
  81. /*
  82.  * Initialize the windows and various other metrics.
  83.  */
  84. public int InitDisplay( fname, display_unit )
  85.   char  *fname;
  86.   char  *display_unit;
  87.   {
  88.     XFontStruct  *font;
  89.  
  90.     if( display == NULL )
  91.       {
  92.     if( (display = XOpenDisplay( display_unit )) == NULL )
  93.       {
  94.         fprintf( stderr, "could not open display\n" );
  95.         return( FALSE );
  96.       }
  97.     screen = ScreenOfDisplay( display, DefaultScreen( display ) );
  98.       }
  99.           
  100.     if( CHARHEIGHT == 0 )
  101.       {
  102.     char  *fontname;
  103.  
  104.     fontname = GetXDefault( DEFL_FONT );
  105.     if( (font = XLoadQueryFont( display, fontname )) == NULL )
  106.       {
  107.         fprintf( stderr, "Could not load font `%s'", fontname );
  108.         if( not IsDefault( DEFL_FONT, fontname ) )
  109.           {
  110.         fontname = ProgDefault( DEFL_FONT );
  111.         if( (font = XLoadQueryFont( display, fontname )) == NULL )
  112.           {
  113.             fprintf( stderr, " or `%s'\n", fontname );
  114.             return( FALSE );
  115.           }
  116.         else
  117.             fprintf( stderr, " using `%s' instead\n", fontname );
  118.           }
  119.         else
  120.           {
  121.         fprintf( stderr, "\n" );
  122.         return( FALSE );
  123.           }
  124.       }
  125.     CHARHEIGHT = font->max_bounds.ascent + font->max_bounds.descent;
  126.     CHARWIDTH = font->max_bounds.width;
  127.     descent = font->max_bounds.descent;
  128.  
  129.     InitGraphics( font->fid );
  130.       }
  131.  
  132.     banner = (fname != NULL and *fname != '\0') ? fname : wname;
  133.     bannerLen = strlen( banner );
  134.  
  135.     if( iconW == 0 )
  136.     iconW = CreateIconWindow( 10, 10 );
  137.  
  138.     if( window == 0 )
  139.       {
  140.     InitWindow( TRUE, NormalState, 0, 0, 0, 0, 10, 10 );
  141.     InitMenus();
  142.       }
  143.  
  144.  
  145.     if( not InitHandler( ConnectionNumber( display ) ) )
  146.     return( FALSE );
  147.  
  148.     return( TRUE );
  149.   }
  150.  
  151.  
  152. public int InitWindow( firstTime, state, x, y, w, h, ix, iy )
  153.   int    firstTime;
  154.   int    state;
  155.   Coord  x, y, w, h;
  156.   Coord  ix, iy;
  157.   {
  158.     int                   spec, u_spec;
  159.     static int            b;
  160.     char                  *geo;
  161.     XSizeHints            shint;
  162.     XWMHints              wmh;
  163.     XSetWindowAttributes  att;
  164.     XClassHint            class;
  165.  
  166.     if( firstTime )
  167.       {
  168.     b = atoi( GetXDefault( DEFL_BDRWIDTH ) );
  169.     if( b <= 0 )
  170.         b = atoi( ProgDefault( DEFL_BDRWIDTH ) );
  171.  
  172.     geo = ProgDefault( DEFL_GEOM );
  173.     spec = XParseGeometry( geo, &x, &y, &w, &h );
  174.     geo = GetXDefault( DEFL_GEOM );
  175.     u_spec = IsDefault( DEFL_GEOM, geo ) ? FALSE : TRUE;
  176.     if( u_spec )
  177.         spec = XParseGeometry( geo, &x, &y, &w, &h );
  178.  
  179.     if( (spec & (XValue | XNegative)) == (XValue | XNegative) )
  180.         x += WidthOfScreen( screen ) - w - 2 * b;
  181.  
  182.     if( (spec & (YValue | YNegative)) == (YValue | YNegative) )
  183.         y += HeightOfScreen( screen ) - h - 2 * b;
  184.  
  185.     XWINDOWSIZE = w;
  186.     YWINDOWSIZE = h;
  187.       }
  188.     else
  189.     u_spec = TRUE;
  190.  
  191.     att.background_pixel = colors.white;
  192.     att.border_pixmap = pix.gray;
  193.     att.backing_planes = colors.black | colors.white | colors.hilite |
  194.      colors.traces | colors.banner_bg | colors.banner_fg;
  195.     att.cursor = cursors.deflt;
  196.  
  197.     window = XCreateWindow( display, RootWindowOfScreen( screen ),
  198.      x, y, w, h, b, DefaultDepthOfScreen( screen ), InputOutput,
  199.      (Visual *) CopyFromParent,
  200.      (CWBackPixel | CWBorderPixmap | CWBackingPlanes | CWCursor), &att );
  201.  
  202.     XStoreName( display, window, wname );
  203.     XSetIconName( display, window, wname );
  204.     class.res_name = "irsim";
  205.     class.res_class = wname;
  206.     XSetClassHint( display, window, &class );
  207.  
  208.     wmh.input = True;
  209.     wmh.initial_state = state;
  210.     wmh.icon_pixmap = pix.icon;
  211.     wmh.icon_window = iconW;
  212.     wmh.icon_x = ix;
  213.     wmh.icon_y = iy;
  214.     wmh.flags = InputHint | StateHint | IconPixmapHint | IconWindowHint |
  215.      IconPositionHint;
  216.     XSetWMHints( display, window, &wmh );
  217.  
  218.     shint.x = x;
  219.     shint.y = y;
  220.     shint.width = w;
  221.     shint.height = h;
  222.     shint.max_width = shint.max_height = 16000;    /* any big number */
  223.     shint.width_inc = shint.height_inc = 1;
  224.     GetMinWsize( &shint.min_width, &shint.min_height );
  225.     shint.flags = ( u_spec ) ?
  226.       ( PMinSize | PMaxSize | PResizeInc | USPosition | USSize ) :
  227.       ( PMinSize | PMaxSize | PResizeInc | PPosition | PSize );
  228.     XSetNormalHints( display, window, &shint );
  229.  
  230.     XSelectInput( display, window, ExposureMask | StructureNotifyMask |
  231.      KeyPressMask | ButtonPressMask | EnterWindowMask | LeaveWindowMask );
  232.     XFlush( display );
  233.   }
  234.  
  235.  
  236. public
  237. #define    DEF_STEPS    4    /* default simulation steps per screen */
  238.  
  239. /*
  240.  * Initialize the display times so that when first called the last time is
  241.  * shown on the screen.  Default width is DEF_STEPS (simulation) steps.
  242.  */
  243. public void InitTimes( firstT, stepsize, lastT )
  244.   TimeType  firstT, stepsize, lastT;
  245.   {
  246.     tims.first = firstT;
  247.     tims.last = lastT;
  248.     tims.steps = 4 * stepsize;
  249.  
  250.     if( autoScroll or tims.start <= tims.first )
  251.       {
  252.     if( lastT < tims.steps )
  253.       {
  254.         tims.start = tims.first;
  255.         tims.end = tims.start + tims.steps;
  256.       }
  257.     else
  258.       {
  259.         tims.end = lastT + 2 * stepsize;
  260.         tims.start = tims.end - tims.steps;
  261.         if( tims.start < tims.first )
  262.           {
  263.         stepsize = tims.first - tims.start;
  264.         tims.start += stepsize;
  265.         tims.end += stepsize;
  266.           }
  267.       }
  268.       }
  269.     tims.cursor = -1;
  270.   }
  271.  
  272.  
  273. /*
  274.  * Redraw any region that overlaps the redraw-box.
  275.  */
  276. public void RedrawWindow( box )
  277.   BBox  box;
  278.   {
  279.     if( Intersect( bannerBox, box ) )
  280.     RedrawBanner();
  281.     if( Intersect( timesBox, box ) )
  282.     RedrawTimes();
  283.     if( Intersect( namesBox, box ) )
  284.     RedrawNames( box );
  285.     if( Intersect( scrollBox, box ) )
  286.     DrawScrollBar( TRUE );
  287.     if( Intersect( cursorBox, box ) )
  288.     DrawCursVal( box );
  289.     if( Intersect( textBox, box ) )
  290.     RedrawText();
  291.     if( Intersect( traceBox, box ) )
  292.     RedrawTraces( &box );
  293.   }
  294.  
  295.  
  296. /*
  297.  * Displays the window banner.
  298.  */
  299. public void RedrawBanner()
  300.   {
  301.     Menu  *mp;
  302.  
  303.     FillBox( window, bannerBox, gcs.bannerBg );
  304.     XCopyArea( display, pix.iconbox, window, gcs.bannerFg, 0, 0, 13, 13, 
  305.      iconBox.left, iconBox.top );
  306.  
  307.     StrLeft( window, banner, bannerLen, iconBox.right + 4,
  308.     (bannerBox.bot - 2 + CHARHEIGHT) / 2, gcs.bannerFg );
  309.  
  310.     if( windowState.selected )
  311.       {
  312.     if( selectBox.right > selectBox.left )
  313.         FillBox( window, selectBox, gcs.select );
  314.     FillAREA( window, bannerBox.left, bannerBox.bot - 1, bannerBox.right -
  315.      bannerBox.left + 1, 2, gcs.border );
  316.     XSetWindowBorder( display, window, colors.border );
  317.       }
  318.     else
  319.       {
  320.     FillAREA( window, bannerBox.left, bannerBox.bot - 1, bannerBox.right -
  321.      bannerBox.left + 1, 2, gcs.gray );
  322.     XSetWindowBorderPixmap( display, window, pix.gray );
  323.       }
  324.  
  325.     for( mp = menu; mp->str != NULL; mp++ )
  326.       {
  327.     StrCenter( window, mp->str, mp->len, mp->box.left, mp->box.right,
  328.      mp->box.bot, gcs.bannerFg );
  329.       }
  330.  
  331.     XCopyArea( display, pix.sizebox, window, gcs.bannerFg, 0, 0, 13, 13, 
  332.      sizeBox.left, sizeBox.top );
  333.   }
  334.  
  335.  
  336. public void WindowCrossed( selected )
  337.   int  selected;
  338.   {
  339.     GC  color;
  340.  
  341.     if( selected == windowState.selected )
  342.     return;
  343.  
  344.     windowState.selected = selected;
  345.     
  346.     if( selected )
  347.     XSetWindowBorder( display, window, colors.border );
  348.     else
  349.     XSetWindowBorderPixmap( display, window, pix.gray );
  350.  
  351.     if( windowState.tooSmall )
  352.     return;
  353.  
  354.     if( selectBox.right > selectBox.left )
  355.       {
  356.     if( selected )
  357.         FillBox( window, selectBox, gcs.select );
  358.     else
  359.         FillBox( window, selectBox, gcs.bannerBg );
  360.       }
  361.     FillAREA( window, bannerBox.left, bannerBox.bot - 1, XWINDOWSIZE - 1, 2,
  362.      selected ? gcs.border : gcs.gray );
  363.   }
  364.  
  365.  
  366. public void RedrawSmallW()
  367.   {
  368.     static  char  *msg = "I'm too small";
  369.     Coord   y;
  370.     int     len;
  371.  
  372.     XClearWindow( display, window );
  373.     len = strlen( msg );
  374.     y = (YWINDOWSIZE - CHARHEIGHT) / 2;
  375.     StrCenter( window, msg, len, 0, XWINDOWSIZE, y, gcs.black );
  376.   }
  377.  
  378.  
  379. public void RedrawTimes()
  380.   {
  381.     char   s[ 20 ];
  382.     int    len;
  383.     Coord  x;
  384.  
  385.     FillAREA( window, 0, timesBox.top, XWINDOWSIZE,
  386.      timesBox.bot - timesBox.top + 1, gcs.white );
  387.  
  388.     (void) sprintf( s, " %.1f ", d2ns( tims.start ) );
  389.     len = strlen( s );
  390.     StrLeft( window, s, len, timesBox.left, timesBox.bot, gcs.white );
  391.     (void) sprintf( s, " %.1f ", d2ns( tims.end ) );
  392.     len = strlen( s );
  393.     StrRight( window, s, len, timesBox.right - 1, timesBox.bot, gcs.white );
  394.     if( tims.cursor >= 0 )
  395.     (void) sprintf( s, "%.1f", d2ns( tims.cursor ) );
  396.     else
  397.     (void) strcpy( s, "-" );
  398.  
  399.     len = strlen( s );
  400.     StrCenter( window, s, len, timesBox.left, timesBox.right, timesBox.bot,
  401.       gcs.black );
  402.   }
  403.  
  404.  
  405. public void UpdateTimes( start, end )
  406.   TimeType  start, end;
  407.   {
  408.     static TimeType  ostart, oend;
  409.     static int       slen, elen;
  410.     int              len;
  411.     char             s[20];
  412.  
  413.     if( start != ostart )
  414.       {
  415.     (void) sprintf( s, " %.1f ", d2ns( start ) );
  416.     len = strlen( s );
  417.     if( len < slen )
  418.         FillAREA( window, timesBox.left + (len * CHARWIDTH), 
  419.          timesBox.bot - CHARHEIGHT - 1, (slen - len) * CHARWIDTH,
  420.          timesBox.bot - timesBox.top + 1, gcs.white );
  421.     StrLeft( window, s, len, timesBox.left, timesBox.bot, gcs.white );
  422.     ostart = start;
  423.     slen = len;
  424.       }
  425.  
  426.     if( end != oend )
  427.       {
  428.     (void) sprintf( s, " %.1f ", d2ns( end ) );
  429.     len = strlen( s );
  430.     if( len < elen )
  431.         FillAREA( window, timesBox.right - (elen * CHARWIDTH),
  432.          timesBox.bot - CHARHEIGHT - 1, (elen - len) * CHARWIDTH,
  433.          timesBox.bot - timesBox.top + 1, gcs.white );
  434.     StrRight( window, s, len, timesBox.right, timesBox.bot, gcs.white );
  435.     oend = len;
  436.     elen = len;
  437.       }
  438.   }
  439.  
  440.  
  441. /*
  442.  * Redraw signal names.
  443.  */
  444. public void RedrawNames( rb )
  445.   BBox  rb;
  446.   {
  447.     Coord  x, y;
  448.     Trptr  t;
  449.     int    i;
  450.  
  451.     rb.left = max( rb.left, namesBox.left );
  452.     rb.right = min( rb.right, namesBox.right );
  453.     rb.top = max( namesBox.top, rb.top );
  454.     rb.bot = min( namesBox.bot, rb.bot );
  455.     FillBox( window, rb, gcs.white );
  456.  
  457.     for( i = traces.disp, t = traces.first; i != 0; i--, t = t->next )
  458.     if( rb.top <= t->bot )
  459.         break;
  460.  
  461.     x = namesBox.right - 2;
  462.     while( i != 0 and rb.bot >= t->top )
  463.       {
  464.     y = (t->bot + t->top + CHARHEIGHT) / 2;
  465.     StrRight( window, t->name, t->len, x, y, gcs.black );
  466.     if( t == selectedTrace )
  467.         UnderlineTrace( t, gcs.black );
  468.     i--;
  469.     t = t->next;
  470.       }
  471.   }
  472.  
  473. #define    CursorVisible( T1, T2 )    (tims.cursor >= (T1) and tims.cursor <= (T2) )
  474.  
  475. /*
  476.  * This will redraw the missing parts of the traces.  Used to selectivelly
  477.  * repaint traces or during Exposure events.
  478.  */
  479. public void RedrawTraces( box )
  480.   BBox  *box;
  481.   {
  482.     TimeType        t1, t2, tc;
  483.     BBox            bg;
  484.     register Trptr  t;
  485.     register int    i;
  486.  
  487.     t1 = XToTime( box->left ) - 1;
  488.     if( t1 < tims.start )
  489.       {
  490.     t1 = tims.start;
  491.     bg.left = traceBox.left;
  492.       }
  493.     else
  494.     bg.left = box->left;
  495.  
  496.     t2 = XToTime( box->right );
  497.     if( t2 < 0 )
  498.       {
  499.     t2 = tims.end;
  500.     bg.right = traceBox.right;
  501.       }
  502.     else
  503.       {
  504.     bg.right = box->right;
  505.     if( t2 < tims.end )
  506.         t2++;
  507.       }
  508.  
  509.     tc = t2;
  510.     if( t2 > tims.last )
  511.     t2 = tims.last;
  512.  
  513.     bg.top = max( box->top, traceBox.top );
  514.     bg.bot = min( box->bot, traceBox.bot );
  515.     if( CursorVisible( t1, tc ) )
  516.     EraseCursor();
  517.  
  518.     FillBox( window, bg, gcs.black );
  519.  
  520.     for( i = traces.disp, t = traces.first; i != 0; i--, t = t->next )
  521.     if( box->top <= t->bot )
  522.         break;
  523.  
  524.     while( i != 0 and box->bot >= t->top )
  525.       {
  526.     if( IsVector( t ) )
  527.         DrawVector( t, t1, t2, FALSE );
  528.     else
  529.         DrawSignal( t, t1, t2 );
  530.     i--;
  531.     t = t->next;
  532.       }
  533.     if( CursorVisible( t1, tc ) )
  534.     DrawCursor();
  535.   }
  536.  
  537.  
  538. /*
  539.  * Update the cache (begining of window and cursor) for traces that just
  540.  * became visible ( or were just added ).
  541.  */
  542. public void UpdateTraceCache( first_trace )
  543.   int  first_trace;
  544.   {
  545.     register Trptr     t;
  546.     register hptr      h,p;
  547.     register int       n, i;
  548.     register TimeType  startT, cursT;
  549.  
  550.     startT = tims.start;
  551.     cursT = max( tims.cursor, tims.first );
  552.     for( t = traces.first, n = 0; n < traces.disp; n++, t = t->next )
  553.       {
  554.     if( n < first_trace )
  555.         continue;
  556.  
  557.     if( t->vector )
  558.       {
  559.         for( i = t->n.vec->nbits - 1; i >= 0; i-- )
  560.           {
  561.         hptr  nexth;
  562.  
  563.         p = t->cache[i].wind;
  564.         h = t->cache[i].cursor;
  565.         NEXTH( nexth, h );
  566.         if( h->time > cursT or nexth->time <= cursT )
  567.           {
  568.             if( p->time <= cursT )    /* whatever is closer */
  569.             t->cache[i].cursor = p;
  570.             else
  571.             t->cache[i].cursor = (hptr)&(t->n.vec->nodes[i]->head);
  572.           }
  573.         if( startT <= p->time )            /* go back */
  574.             p = (hptr) &(t->n.vec->nodes[i]->head);
  575.  
  576.         NEXTH( h, p );
  577.         while( h->time < startT )
  578.           {
  579.             p = h;
  580.             NEXTH( h, h );
  581.           }
  582.         t->cache[i].wind = p;
  583.  
  584.         p = t->cache[i].cursor;
  585.         NEXTH( h, p );
  586.         while( h->time <= cursT )
  587.           {
  588.             p = h;
  589.             NEXTH( h, h );
  590.           }
  591.         t->cache[i].cursor = p;
  592.           }
  593.       }
  594.     else
  595.       {
  596.         hptr  nexth;
  597.  
  598.         p = t->cache[0].wind;
  599.         h = t->cache[0].cursor;
  600.         NEXTH( nexth, h );
  601.         if( h->time > cursT or nexth->time <= cursT )
  602.           {
  603.         if( p->time <= cursT )
  604.             t->cache[0].cursor = p;
  605.         else
  606.             t->cache[0].cursor = (hptr) &(t->n.nd->head);
  607.           }
  608.  
  609.         if( startT <= p->time )
  610.         p = (hptr) &(t->n.nd->head);
  611.  
  612.         NEXTH( h, p );
  613.         while( h->time < startT )
  614.           {
  615.         p = h;
  616.         NEXTH( h, h );
  617.           }
  618.         t->cache[0].wind = p;
  619.  
  620.         p = t->cache[0].cursor;
  621.         NEXTH( h, p );
  622.         while( h->time <= cursT )
  623.           {
  624.         p = h;
  625.         NEXTH( h, h );
  626.           }
  627.         t->cache[0].cursor = p;
  628.       }
  629.       }
  630.   }
  631.  
  632.  
  633. private    TimeType  lastStart;        /* last redisplay starting time */
  634.  
  635.  
  636. public void FlushTraceCache()
  637.   {
  638.     lastStart = max_time;
  639.   }
  640.  
  641.  
  642. /*
  643.  * Draw the traces horizontally from time1 to time2.
  644.  */
  645. public void DrawTraces( t1, t2 )
  646.   TimeType  t1, t2;
  647.   {
  648.     TimeType         endT;
  649.     register Trptr   t;
  650.     int              nt;
  651.  
  652.     if( t1 == tims.start )
  653.     FillBox( window, traceBox, gcs.black );
  654.     else if( colors.disj == 0 and CursorVisible( tims.start, t2 ) )
  655.     EraseCursor();
  656.  
  657.     if( tims.start != lastStart )        /* Update history cache */
  658.       {
  659.     int                begin;
  660.     register TimeType  startT;
  661.     register int       n, i;
  662.     register hptr      h, p;
  663.  
  664.     startT = tims.start;
  665.     begin = ( startT < lastStart );
  666.     for( t = traces.first, n = traces.disp; n != 0; n--, t = t->next )
  667.       {
  668.         if( t->vector )
  669.           {
  670.         for( i = t->n.vec->nbits - 1; i >= 0; i-- )
  671.           {
  672.             p = begin ? (hptr) &(t->n.vec->nodes[i]->head) : t->cache[i].wind;
  673.             NEXTH( h, p );
  674.             while( h->time < startT )
  675.               {
  676.             p = h;
  677.             NEXTH( h, h );
  678.               }
  679.             t->cache[i].wind = p;
  680.           }
  681.           }
  682.         else
  683.           {
  684.         p = begin ? (hptr) &(t->n.nd->head) : t->cache[0].wind;
  685.         NEXTH( h, p );
  686.         while( h->time < startT )
  687.           {
  688.             p = h;
  689.             NEXTH( h, h );
  690.           }
  691.         t->cache[0].wind = p;
  692.           }
  693.       }
  694.     lastStart = tims.start;
  695.       }
  696.  
  697.     endT = min( t2, tims.last );
  698.  
  699.     for( t = traces.first, nt = traces.disp; nt != 0; nt--, t = t->next )
  700.       {
  701.     if( IsVector( t ) )
  702.         DrawVector( t, t1, endT, (t1 != tims.start) ? TRUE : FALSE );
  703.     else
  704.         DrawSignal( t, t1, endT );
  705.       }
  706.     if( CursorVisible( tims.start, t2 ) )
  707.     DrawCursor();
  708.   }
  709.  
  710.  
  711. /*
  712.  * Draw a 1 bit trace.
  713.  */
  714. private void DrawSignal( t, t1, t2 )
  715.   Trptr              t;
  716.   register TimeType  t1, t2;
  717.   {
  718.     register hptr  h;
  719.     register int   val, change;
  720.     int            x1, x2;
  721.  
  722.     if( t1 >= tims.last )
  723.     return;
  724.  
  725.     h = t->cache[0].wind;
  726.     if( t1 != tims.start )
  727.       {
  728.     register hptr  n;
  729.  
  730.     NEXTH( n, h );
  731.     while( n->time < t1 )
  732.       {
  733.         h = n;
  734.         NEXTH( n, n );
  735.       }
  736.       }
  737.  
  738.     x1 = TimeToX( t1 );
  739.     while( t1 < t2 )
  740.       {
  741.     val = h->val;
  742.     while( h->time < t2 and h->val == val )
  743.         NEXTH( h, h );
  744.     if( h->time > t2 )
  745.       {
  746.         change = FALSE;
  747.         t1 = t2;
  748.       }
  749.     else
  750.       {
  751.         change = ( h->val != val );
  752.         t1 = h->time;
  753.       }
  754.     x2 = TimeToX( t1 );
  755.     switch( val )
  756.       {
  757.         case LOW :
  758.         HLine( window, x1, x2, t->bot, gcs.traceFg );
  759.         break;
  760.         case HIGH :
  761.         HLine( window, x1, x2, t->top, gcs.traceFg );
  762.         break;
  763.         case X :
  764.         if( x1 > traceBox.left + 1 )
  765.             x1++;
  766.         FillAREA( window, x1, t->top, x2 - x1 + 1, t->bot - t->top + 1,
  767.           gcs.xpat );
  768.         break;
  769.       }
  770.     if( change )
  771.         VLine( window, x2, t->bot, t->top, gcs.traceFg );
  772.     x1 = x2;
  773.       }
  774.   }
  775.  
  776.  
  777. public    hptr    tmpHBuff[ 400 ];
  778.  
  779. /*
  780.  * Draw bus trace.
  781.  */
  782. private void DrawVector( t, t1, t2, clr_bg )
  783.   register Trptr     t;
  784.   register TimeType  t1, t2;
  785.   int                clr_bg;
  786.   {
  787.     hptr      *start, *changes;
  788.     TimeType  firstChange;
  789.     int       x1, x2, xx, mid, nbits, strlen, strwidth;
  790.     
  791.     if( t1 >= tims.last )
  792.     return;
  793.  
  794.     nbits = t->n.vec->nbits;
  795.     start = tmpHBuff;
  796.     changes = &(tmpHBuff[ nbits ]);
  797.     strlen = (nbits + t->bdigit - 1) / t->bdigit;
  798.     strwidth = CHARWIDTH * strlen + 1;
  799.  
  800.       {
  801.     register hptr  h, *s;
  802.     register int   n, val;
  803.  
  804.     s = start;            /* initialize start array */
  805.     if( t1 != tims.start )
  806.       {
  807.         register hptr  p;
  808.  
  809.         firstChange = tims.start;
  810.         for( n = nbits - 1; n >= 0; n-- )
  811.           {
  812.         p = t->cache[n].wind;
  813.         val = p->val;
  814.         NEXTH( h, p );
  815.         while( h->time < t1 )
  816.           {
  817.             if( h->val != val )
  818.               {
  819.             if( h->time > firstChange )
  820.                 firstChange = h->time;
  821.             val = h->val;
  822.               }
  823.             p = h;
  824.             NEXTH( h, h );
  825.           }
  826.         s[n] = p;
  827.           }
  828.       }
  829.     else
  830.       {
  831.         firstChange = tims.start;
  832.         for( n = nbits - 1; n >= 0; n-- )
  833.         s[n] = t->cache[n].wind;
  834.       }
  835.  
  836.       {    /* Initialize changes array */
  837.         register hptr      *ch = changes;
  838.         register TimeType  tm = tims.end;
  839.  
  840.         for( n = nbits - 1; n >= 0; n-- )
  841.           {
  842.         h = s[n];
  843.         val = h->val;
  844.         while( h->time < tm and h->val == val )
  845.             NEXTH( h, h );
  846.         ch[n] = h;
  847.           }
  848.       }
  849.       }
  850.  
  851.     mid = (t->top + t->bot + CHARHEIGHT) / 2;
  852.     xx = TimeToX( t1 );
  853.     x2 = TimeToX( t2 );
  854.     x1 = TimeToX( firstChange );
  855.     HLine( window, xx, x2, t->top, gcs.traceFg );
  856.     HLine( window, xx, x2, t->bot, gcs.traceFg );
  857.     if( clr_bg and t1 != tims.start and (xx - x1) > strwidth )
  858.     FillAREA( window, x1+1, mid - CHARHEIGHT+1, xx - x1+1, CHARHEIGHT,
  859.      gcs.traceBg );
  860.  
  861.     while( t1 < t2 )
  862.       {
  863.       {                /* find nearest change in time */
  864.         register hptr  *ch;
  865.         register int   n;
  866.  
  867.         t1 = tims.end + 1;
  868.         for( ch = changes, n = nbits - 1; n >= 0; n-- )
  869.           {
  870.         if( ch[n]->time < t1 )
  871.             t1 = ch[n]->time;
  872.           }
  873.       }
  874.  
  875.     if( t1 <= t2 )            /* change before t2 => draw it */
  876.       {
  877.         register int  n;
  878.  
  879.         x2 = TimeToX( t1 );
  880.         n = (x2 == traceBox.left+1) ? 2 : (x2 == traceBox.right-1) ? 1 : 0;
  881.         VLine( window, x2, t->bot, t->top, gcs.traceFg );
  882.         XCopyArea( display, pix.tops[n], window, gcs.traceBg, 0, 0, 3, 2,
  883.          x2 - 1, t->top );
  884.         XCopyArea( display, pix.bots[n], window, gcs.traceBg, 0, 0, 3, 2,
  885.          x2 - 1, t->bot - 1 );
  886.       }
  887.     else                /* change after t2 */
  888.       {
  889.         register TimeType  tm;
  890.  
  891.         tm = min( t1, min( tims.end, tims.last ) );
  892.         x2 = TimeToX( tm );
  893.       }
  894.  
  895.     if( x2 - x1 > strwidth )
  896.       {
  897.         char  *str;
  898.         str = HistToStr( start, nbits, t->bdigit, 1 );
  899.         StrCenter( window, str, strlen, x1, x2, mid, gcs.traceFg );
  900.       }
  901.  
  902.       {
  903.         register hptr      h;
  904.         register hptr      *ch, *s;
  905.         register int       n, val;
  906.         register TimeType  tm = tims.end;
  907.  
  908.         for( s = start, ch = changes, n = nbits - 1; n >= 0; n-- )
  909.           {
  910.         if( ch[n]->time == t1 )
  911.           {
  912.             h = s[n] = ch[n];
  913.             val = h->val;
  914.             while( h->time < tm and h->val == val )
  915.             NEXTH( h, h );
  916.             ch[n] = h;
  917.           }
  918.           }
  919.       }
  920.     x1 = x2;
  921.       }
  922.   }
  923.  
  924.  
  925.  
  926. private void UpdateTraces( start, end )
  927.   TimeType  start, end;
  928.   {
  929.     if( not (windowState.iconified or windowState.tooSmall) )
  930.       {
  931.     UpdateScrollBar();
  932.     RedrawTimes();
  933.     DrawTraces( start, end );
  934.       }
  935.   }
  936.  
  937.  
  938. private void ScrollTraces( endT )
  939.   TimeType  endT;
  940.   {
  941.     tims.start = endT - tims.steps / 2;
  942.     tims.end = tims.start + tims.steps;
  943.     UpdateTraces( tims.start, endT );
  944.   }
  945.  
  946.  
  947. /*
  948.  * Update the trace window so that endT is shown.  If the update fits in the
  949.  * window, simply draw the missing parts.  Otherwise scroll the traces,
  950.  * centered around endT.
  951.  */
  952. public void UpdateWindow( endT )
  953.   TimeType  endT;
  954.   {
  955.     TimeType  lastT;
  956.  
  957.     DisableInput();
  958.  
  959.     if( freezeWindow )
  960.       {
  961.     updatePending = TRUE;
  962.     updPendTime = endT;
  963.       }
  964.     else
  965.       {
  966.     lastT = tims.last;
  967.     tims.last = endT;
  968.  
  969.     if( endT <= tims.end )
  970.       {
  971.         if( lastT >= tims.start )
  972.         UpdateTraces( lastT, endT );
  973.         else if( autoScroll )
  974.         ScrollTraces( endT );
  975.         else if( endT > tims.start )
  976.         UpdateTraces( tims.start, endT );
  977.       }
  978.     else                    /* endT > tims.end */
  979.       {
  980.         if( autoScroll )
  981.         ScrollTraces( endT );
  982.         else if( lastT < tims.end )
  983.         UpdateTraces( lastT, tims.end );
  984.       }
  985.       }
  986.     EnableInput();
  987.   }
  988.  
  989.  
  990. /*
  991.  * Erase/Redraw the cursor.
  992.  */
  993. private void EraseCursor()
  994.   {
  995.     Coord  x;
  996.     
  997.     x = TimeToX( tims.cursor );
  998.     FillAREA( window, x, traceBox.top, 1, traceBox.bot - traceBox.top,
  999.      gcs.curs_off );
  1000.   }
  1001.  
  1002.  
  1003. private void  DrawCursor()
  1004.   {
  1005.     Coord  x;
  1006.     
  1007.     x = TimeToX( tims.cursor );
  1008.     FillAREA( window, x, traceBox.top, 1, traceBox.bot - traceBox.top,
  1009.      gcs.curs_on );
  1010.   }
  1011.  
  1012.  
  1013. public void DoCursor( ev )
  1014.   XButtonEvent  *ev;
  1015.   {
  1016.     Trptr     t;
  1017.     TimeType  time;
  1018.     char      tbuff[15];
  1019.  
  1020.     if( not (ev->state & ShiftMask) )
  1021.       {
  1022.     MoveCursorToPos( ev->x );
  1023.     return;
  1024.       }
  1025.  
  1026.     t = GetYTrace( ev->y );
  1027.     time = XToTime( ev->x );
  1028.     if( t == NULL or time < 0 or time > tims.last )
  1029.       {
  1030.     XBell( display, 0 );
  1031.     return;
  1032.       }
  1033.     (void) sprintf( tbuff, "%.1f", d2ns( time ) );
  1034.     PRINTF( "\n%s @ %s: value=", t->name, tbuff );
  1035.       {
  1036.     register hptr  h, p;
  1037.     register int   n;
  1038.     register char  *val, *inp;
  1039.     int            nbits;
  1040.  
  1041.     val = (char *) tmpHBuff;
  1042.     if( IsVector( t ) )
  1043.         nbits = t->n.vec->nbits;
  1044.     else
  1045.         nbits = 1;
  1046.         
  1047.     inp = &(val[nbits]);
  1048.     *inp++ = '\0';
  1049.     inp[nbits] = '\0';
  1050.     for( n = nbits - 1; n >= 0; n-- )
  1051.       {
  1052.         p = t->cache[n].wind;
  1053.         NEXTH( h, p );
  1054.         while( h->time <= time )
  1055.           {
  1056.         p = h;
  1057.         NEXTH( h, h );
  1058.           }
  1059.         val[n] = "0X 1"[ p->val ];
  1060.         inp[n] = "-i"[p->inp];
  1061.       }
  1062.     PRINTF( "%s, input=%s", val, inp );
  1063.       }
  1064.   }
  1065.  
  1066.  
  1067. private void MoveCursorToPos( x )
  1068.   Coord  x;
  1069.   {
  1070.     register int       i;
  1071.     register Trptr     t;
  1072.     register TimeType  time;
  1073.     char               s[ 20 ];
  1074.     static int         olen = 1;
  1075.  
  1076.     time = XToTime( x );
  1077.     if( time == tims.cursor or time < tims.start or time > tims.end )
  1078.     return;
  1079.  
  1080.     if( CursorVisible( tims.start, tims.end ) )
  1081.     EraseCursor();
  1082.  
  1083.     tims.cursor = time;
  1084.     DrawCursor();
  1085.     (void) sprintf( s, "%.1f", d2ns( time ) );
  1086.     i = strlen( s );
  1087.     if( i < olen )
  1088.       {
  1089.     FillAREA( window, (timesBox.left+timesBox.right+(olen * CHARWIDTH))/2,
  1090.     timesBox.bot - CHARHEIGHT - 1, olen * CHARWIDTH,
  1091.     timesBox.bot - timesBox.top + 1, gcs.white );
  1092.       }    
  1093.     StrCenter( window, s, i, timesBox.left, timesBox.right, timesBox.bot,
  1094.        gcs.black );
  1095.     for( i = traces.disp, t = traces.first; i != 0; i--, t = t->next )
  1096.       {
  1097.     register hptr   h, p;
  1098.  
  1099.     if( IsVector( t ) )
  1100.       {
  1101.         register int  n;
  1102.  
  1103.         for( n = t->n.vec->nbits - 1; n >= 0; n-- )
  1104.           {
  1105.         p = t->cache[n].wind;
  1106.         NEXTH( h, p );
  1107.         while( h->time <= time )
  1108.           {
  1109.             p = h;
  1110.             NEXTH( h, h );
  1111.           }
  1112.         t->cache[n].cursor = p;
  1113.           }
  1114.       }
  1115.     else
  1116.       {
  1117.         p = t->cache[0].wind;
  1118.         NEXTH( h, p );
  1119.         while( h->time <= time )
  1120.           {
  1121.         p = h;
  1122.         NEXTH( h, h );
  1123.           }
  1124.         t->cache[0].cursor = p;
  1125.       }
  1126.       }
  1127.     DrawCursVal( cursorBox );
  1128.   }
  1129.  
  1130. private    char  *StrMap[] = { "0", "X", "", "1" };
  1131.  
  1132.  
  1133. /*
  1134.  * Display signal values under cursor.
  1135.  */
  1136. public void DrawCursVal( rb )
  1137.   BBox  rb;
  1138.   {
  1139.     Coord        y;
  1140.     Trptr        t;
  1141.     int          i, len;
  1142.     char         *val;
  1143.  
  1144.     rb.left = max( rb.left, cursorBox.left );
  1145.     rb.right = min( rb.right, cursorBox.right );
  1146.     rb.top = max( cursorBox.top, rb.top );
  1147.     rb.bot = min( cursorBox.bot, rb.bot );
  1148.     FillBox( window, rb, gcs.white );
  1149.  
  1150.     if( tims.cursor < tims.first or tims.cursor > tims.last )
  1151.     return;
  1152.  
  1153.     for( i = traces.disp, t = traces.first; i != 0; i--, t = t->next )
  1154.     if( rb.top <= t->bot )
  1155.         break;
  1156.  
  1157.     while( i != 0 and rb.bot >= t->top )
  1158.       {
  1159.     y = ( t->bot + t->top + CHARHEIGHT ) / 2;
  1160.     val = IsVector( t ) ?
  1161.         HistToStr( &(t->cache[0].cursor), t->n.vec->nbits, t->bdigit, 2 ) :
  1162.         StrMap[ t->cache[0].cursor->val ];
  1163.  
  1164.     len = strlen( val );
  1165.     StrCenter( window, val, len, cursorBox.left, cursorBox.right, y,
  1166.      gcs.black );
  1167.     i--;
  1168.     t = t->next;
  1169.       }
  1170.   }
  1171.  
  1172.  
  1173. public void ExpandCursVal( t )
  1174.   Trptr  t;
  1175.   {
  1176.     char          *val;
  1177.     int           nbits;
  1178.  
  1179.     nbits = IsVector( t ) ? t->n.vec->nbits : 1;
  1180.     val = HistToStr( &(t->cache[0].cursor), nbits, 1, 2 );
  1181.  
  1182.     PRINTF( "\n %s : value=%s", t->name, val );
  1183.       {
  1184.     register int    n;
  1185.     register Cache  *c;
  1186.     register char   *s;
  1187.  
  1188.     for( n = 0, s = val, c = t->cache; n < nbits; n++ )
  1189.         *s++ = ( c[n].cursor->inp) ? 'i' : '-';
  1190.       }
  1191.     PRINTF( "  input=%s", val );
  1192.   }
  1193.